package su.msk.jet.team01.chatik.server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Server {

	private List<NetworkClient> networkClients = new ArrayList<NetworkClient>();
	
	private static Logger logger = LoggerFactory.getLogger(Server.class);

	private ServerSocket providerSocket = null;

	public void shutdown() {
		logger.info("Stopping the server...");

		try {
			providerSocket.close();
		} catch (IOException e) {
			logger.error("Can't close server listening socket."
					+ " Error message :" + e.getMessage());
		}

		disconnectAll();

		logger.info("Exiting now");
	}

	private void addNetworkClient(NetworkClient networkClient) {
		synchronized (networkClients) {
			networkClients.add(networkClient);
		}
	}
	
	public void start(final int port) {
		NetworkClient networkClient;
		Socket socket;

		try {
			providerSocket = new ServerSocket(port);

			logger.info("Server started, waiting for clients on port " + port);
			while (true) {
				socket = providerSocket.accept();
				networkClient = new NetworkClient(this, socket);
				addNetworkClient(networkClient);
				logger.info("Client (" + networkClient.getIP() + ") connected.");
				networkClient.start();
			}
		} catch (IOException e) {
			logger.info("Listen connection thread closed");
		} finally {
			if (providerSocket != null) {
				try {
					providerSocket.close();
				} catch (Exception ex) {
					logger.error("Error closing socket.", ex);
				}
			}
		}
	}

	public void disconnectNetworkClient(NetworkClient networkClient) {
		synchronized(networkClients) {
			networkClients.remove(networkClient);
		}
		
		try {
			networkClient.getClient().remove();

			networkClient.getInput().close();
			networkClient.getOutput().close();
			networkClient.getSocket().close();
		} catch (Exception ex) {
			logger.warn("Closing connection error.", ex);
		}
	}
	
	public void disconnectAll() {
		Object[] copy;

		synchronized (networkClients) {
			copy = networkClients.toArray();
		}
		
		for (Object networkClient : copy) {
			disconnectNetworkClient((NetworkClient)networkClient);
		}
	}
}
